package com.smartwebx.fr.util;

import java.awt.Point;
import java.awt.Rectangle;
import java.util.List;

import com.aspose.words.Cell;
import com.aspose.words.CellFormat;
import com.aspose.words.CellMerge;
import com.aspose.words.CellVerticalAlignment;
import com.aspose.words.DocumentBuilder;
import com.aspose.words.ParagraphAlignment;
import com.aspose.words.Row;
import com.aspose.words.Table;
import com.google.common.base.Splitter;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.primitives.Ints;
import com.smartwebx.fr.bean.FreeTable;
import com.smartwebx.fr.bean.MergedCellInfo;
import com.smartwebx.fr.bean.SmartTable;

public class AsponTableUtil {

	@SuppressWarnings("unchecked")
	public static Table buildTable(SmartTable smartTable,
			DocumentBuilder builder) throws Exception {
		Table table = null;
		String type = smartTable.getDataType();
		if ("table".equals(type)) {
			table = buildAsponTable(
					(List<List<String>>) smartTable.getTableData(), builder);
		} else if ("freeTable".equals(type)) {
			table = buildAsponFreeTable((FreeTable) smartTable.getTableData(),
					builder);
		}

		return table;
	}

	private static Table buildAsponTable(List<List<String>> tableData,
			DocumentBuilder builder) throws Exception {
		List<List<SmartTablePoint>> asponTable = Lists.newArrayList();
		for (int i = 0; i < tableData.size(); i++) {
			List<SmartTablePoint> smartLines = Lists.newArrayList();
			asponTable.add(smartLines);
		}

		int currRow = 1;
		for (List<String> line : tableData) {
			int cellIndex = 0;
			for (String point : line) {
				// 分割字符串 text::rowspan::colspan
				Iterable<String> pointSplitter = Splitter.on("::").split(point);
				String text = "";
				Integer rowspan = 0;
				Integer colspan = 0;
				if (Iterables.size(pointSplitter) == 3) {
					text = Iterables.get(pointSplitter, 0);
					rowspan = Ints.tryParse(Iterables.get(pointSplitter, 1));
					colspan = Ints.tryParse(Iterables.get(pointSplitter, 2));

					smartTablePoint(cellIndex, text, rowspan, colspan, currRow,
							asponTable, true);
				}
				cellIndex++;
			}
			currRow++;
		}

		Table table = builder.startTable();
		for (List<SmartTablePoint> smartLine : asponTable) {
			for (SmartTablePoint smartPoint : smartLine) {
				builder.insertCell();
				CellFormat cellFormat = builder.getCellFormat();
				cellFormat.setVerticalMerge(smartPoint.verticalMergeType);
				cellFormat.setHorizontalMerge(smartPoint.horizontalMergeType);
				cellFormat.setVerticalAlignment(CellVerticalAlignment.CENTER);
				builder.getParagraphFormat().setAlignment(
						ParagraphAlignment.CENTER);
				builder.write(smartPoint.text);
			}
			builder.endRow();
		}
		builder.endTable();

		return table;
	}

	private static Table buildAsponFreeTable(FreeTable freeTable,
			DocumentBuilder builder) throws Exception {
		List<List<String>> tabData = freeTable.getData();
		List<MergedCellInfo> mergedCellInfos = freeTable.getMergedCellInfos();

		Table table = builder.startTable();
		for (List<String> line : tabData) {
			for (String point : line) {
				if (point == null) {
					point = "";
				}
				builder.insertCell();
				CellFormat cellFormat = builder.getCellFormat();
				cellFormat.setVerticalAlignment(CellVerticalAlignment.CENTER);
				builder.getParagraphFormat().setAlignment(
						ParagraphAlignment.CENTER);
				builder.write(point);
			}
			builder.endRow();
		}
		builder.endTable();

		for (MergedCellInfo mergedInfo : mergedCellInfos) {
			int row = mergedInfo.getRow();
			int rowspan = mergedInfo.getRowspan();
			int col = mergedInfo.getCol();
			int colspan = mergedInfo.getColspan();

			Cell startCell = table.getRows().get(row).getCells().get(col);
			Cell endCell = table.getRows().get(row + rowspan - 1).getCells()
					.get(col + colspan - 1);

			mergeCell(startCell, endCell);
		}

		return table;
	}

	private static void mergeCell(Cell startCell, Cell endCell) {
		Table parentTable = startCell.getParentRow().getParentTable();

		Point startCellPos = new Point(startCell.getParentRow().indexOf(
				startCell), parentTable.indexOf(startCell.getParentRow()));
		Point endCellPos = new Point(endCell.getParentRow().indexOf(endCell),
				parentTable.indexOf(endCell.getParentRow()));
		Rectangle mergeRange = new Rectangle(Math.min(startCellPos.x,
				endCellPos.x), Math.min(startCellPos.y, endCellPos.y),
				Math.abs(endCellPos.x - startCellPos.x) + 1,
				Math.abs(endCellPos.y - startCellPos.y) + 1);

		for (Row row : parentTable.getRows()) {
			for (Cell cell : row.getCells()) {
				Point currentPos = new Point(row.indexOf(cell),
						parentTable.indexOf(row));
				if (mergeRange.contains(currentPos)) {
					if (currentPos.x == mergeRange.x)
						cell.getCellFormat()
								.setHorizontalMerge(CellMerge.FIRST);
					else
						cell.getCellFormat().setHorizontalMerge(
								CellMerge.PREVIOUS);

					if (currentPos.y == mergeRange.y)
						cell.getCellFormat().setVerticalMerge(CellMerge.FIRST);
					else
						cell.getCellFormat().setVerticalMerge(
								CellMerge.PREVIOUS);
				}
			}
		}
	}

	/**
	 * 根据 html table cell 构造 docx table
	 * 
	 * @param cellIndex
	 *            当前行数据点的索引
	 * @param cellText
	 *            数据点值
	 * @param rowspan
	 *            合并行
	 * @param colspan
	 *            合并列
	 * @param currRow
	 *            当前行索引 从 1 开始
	 * @param smartTable
	 *            存放构造 docx table 信息
	 * @param isStart
	 *            true 上级调用的；false 递归调用的
	 */
	private static void smartTablePoint(int cellIndex, String cellText,
			int rowspan, int colspan, int currRow,
			List<List<SmartTablePoint>> smartTable, boolean isStart) {
		// 获取当前数据行
		List<SmartTablePoint> currHeadLines = smartTable.get(currRow - 1);
		int linesSize = currHeadLines.size();
		SmartTablePoint smartPoint = null;

		// 判断当前索引是否大于当前行的容量，如果大于则扩充到当前索引的容量
		// 如果不大于，则以当前索引的位置查找伪位数对象，异常则实例化一个伪数据放入容器，并赋值给当前对象
		if (linesSize < (cellIndex + 1)) {
			int lastSize = cellIndex - linesSize;
			for (; lastSize >= 0; lastSize--) {
				SmartTablePoint tmp = new SmartTablePoint();
				currHeadLines.add(tmp);
				if (lastSize == 0) {
					smartPoint = tmp;
				}
			}
		} else {
			int tmp = cellIndex;
			for (;;) {
				try {
					smartPoint = currHeadLines.get(tmp++);
				} catch (IndexOutOfBoundsException ioe) {// 数据越界
					SmartTablePoint tmpSHP = new SmartTablePoint();
					currHeadLines.add(tmpSHP);
					smartPoint = tmpSHP;
					break;
				}
				if (!smartPoint.isReal)
					break;
			}
		}

		int verticalMergeType = CellMerge.NONE, horizontalMergeType = CellMerge.NONE;
		if (!isStart) {// 递归调调用时，垂直初始化合并项
			verticalMergeType = CellMerge.PREVIOUS;
		}

		if (rowspan > 1) {
			if (isStart) {
				verticalMergeType = CellMerge.FIRST;
			}
		}
		if (colspan > 1) {
			horizontalMergeType = CellMerge.FIRST;
		}

		// 存入真实数据
		smartPoint.pullSmartHeadPoint(cellText, horizontalMergeType,
				verticalMergeType);
		// 构造向后合并数据
		for (int tmp = colspan - 1; tmp > 0; tmp--) {
			verticalMergeType = CellMerge.NONE;
			if (rowspan >= 1) {
				verticalMergeType = CellMerge.PREVIOUS;
			}

			horizontalMergeType = CellMerge.NONE;
			if (tmp >= 1) {
				horizontalMergeType = CellMerge.PREVIOUS;
			}

			smartPoint = new SmartTablePoint("", horizontalMergeType,
					verticalMergeType);
			currHeadLines.add(smartPoint);
		}

		if (rowspan > 1) {// 判读是否要向下合并
			smartTablePoint(cellIndex, "", --rowspan, colspan, ++currRow,
					smartTable, false);
		}
	}

	static class SmartTablePoint {
		String text;
		int horizontalMergeType;// 水平合并
		int verticalMergeType;// 垂直合并
		boolean isReal = false;

		public SmartTablePoint(String text, int horizontalMergeType,
				int verticalMergeType) {
			super();
			this.text = text;
			this.horizontalMergeType = horizontalMergeType;
			this.verticalMergeType = verticalMergeType;
			this.isReal = true;
		}

		public void pullSmartHeadPoint(String text, int horizontalMergeType,
				int verticalMergeType) {
			this.text = text;
			this.horizontalMergeType = horizontalMergeType;
			this.verticalMergeType = verticalMergeType;
			this.isReal = true;
		}

		public SmartTablePoint() {
		}

		@Override
		public String toString() {
			String txt = this.text;
			String hType = "NONE";
			String vType = "NONE";
			if (CellMerge.FIRST == horizontalMergeType) {
				hType = "FIRST";
			} else if (CellMerge.PREVIOUS == horizontalMergeType) {
				hType = "PREVIOUS";
			} else if (CellMerge.NONE == horizontalMergeType) {
				hType = "NONE";
			}

			if (CellMerge.FIRST == verticalMergeType) {
				vType = "FIRST";
			} else if (CellMerge.PREVIOUS == verticalMergeType) {
				vType = "PREVIOUS";
			} else if (CellMerge.NONE == verticalMergeType) {
				vType = "NONE";
			}

			return txt + "[" + hType + "," + vType + "]";
		}
	}
}
